package com.qen.service;

import com.alibaba.fastjson2.JSONObject;
import com.qen.common.BeetlUtils;
import com.qen.common.ChainWrappers;
import com.qen.conditions.query.LambdaQueryChainWrapper;
import com.qen.conditions.query.QueryChainWrapper;
import com.qen.conditions.update.LambdaUpdateChainWrapper;
import com.qen.conditions.update.UpdateChainWrapper;
import com.qen.repository.BaseDao;
import com.qen.wrapper.Wrapper;
import com.qen.wrapper.Wrappers;
import com.qen.wrapper.update.LambdaUpdateWrapper;
import com.qen.wrapper.update.UpdateWrapper;
import org.beetl.sql.core.page.DefaultPageRequest;
import org.beetl.sql.core.page.PageRequest;
import org.beetl.sql.core.page.PageResult;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * @author licz
 * @data 2025年05月22日 3:23 PM
 */
public interface IService<T> {

    /**
     * 获取对应 entity 的 Dao
     *
     * @return BaseDao
     */
    BaseDao<T> getBaseDao();

    /**
     * 获取 entity 的 class
     *
     * @return {@link Class<T>}
     */
    Class<T> getEntityClass();

    /**
     * 主键查询.
     *
     * @param key 主键
     * @return 数据实体类
     */
    T findObjectByKey(Serializable key);

    /**
     * 主键查询.
     *
     * @param idList 主键
     * @return 数据实体类
     */
    List<T> findObjectByKey(List<? extends Serializable> idList);

    /**
     * sql查询.
     *
     * @param sql             sql语句
     * @param params          参数键值对,in/not in的参数 是数组
     * @param pageNum         分页页数
     * @param pageSize        分页数量
     * @param isTotalRequired 是否返回总数
     * @return 返回PageResult对象，如果isTotalRequired为true 则返回总数；getTotalRow:总数；getList:数据集合;getTotalPage 总页数；
     */
    PageResult<T> queryEntityListPageable(String sql, Map<String, Object> params, int pageNum, int pageSize, boolean isTotalRequired);

    /**
     * 根据sql查询对象集合
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回指定的clz对象的集合
     */
    List<T> queryEntityList(String sql, Map<String, Object> params);

    /**
     * 根据sql查询对象集合
     *
     * @param sql    sql语句
     * @param params 实体对象
     * @return 返回指定的clz对象的集合
     */
    List<T> queryEntityList(String sql, Object params);

    /**
     * 使用Markdown格式来组织SQL文件
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回指定的clz对象的集合
     */
    List<T> queryEntityListFromMarkdown(String fileName, String sqlMark, Map<String, Object> params);

    /**
     * T 对象的 库更新，obj中需要主键，没有就不更新
     *
     * @param obj
     */
    void updateIfNotNull(Map<String, Object> obj);

    /**
     * 根据主键删除T对象.
     *
     * @param key 主键
     */
    void deleteEntityByKey(Serializable key);

    /**
     * 部分更新，实体类中属性为Null或不传入的则不被更新
     *
     * @param list 任意类型对象List,未考虑到数据库能接收的最大量，因此，还需要程序自己控制每批的数量，设置成每批3000个比较通用
     */
    void updateBatchIfNotNull(List<T> list);

    /**
     * 批量添加添加对象
     *
     * @param list
     * @param <E>
     */
    <E> void addBatch(List<E> list);


    /**
     * 查对象
     *
     * @param key
     * @param clz
     * @param <E>
     * @return
     */
    <E> E findObjectByKey(Serializable key, Class<E> clz);

    /**
     * 查对象
     *
     * @param keys
     * @param clz
     * @param <E>
     * @return
     */
    <E> List<E> findObjectByKey(List<? extends Serializable> keys, Class<E> clz);

    /**
     * sql查询,适用查询结果单行的场景；
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @param clz    指定返回的list中存放的对象的class,如String.class,Integer.Class,Double.Class
     * @param <E>    返回类型
     * @return 返回查询结果
     */
    default <E> E querySingleObject(String sql, Map<String, Object> params, Class<E> clz, boolean strictMode) {
        return querySingleObject(sql, (Object) params, clz, strictMode);
    }

    /**
     * sql查询,适用查询结果单行的场景；
     *
     * @param sql    sql语句
     * @param params 传参可以是实体对象
     * @param clz    指定返回的list中存放的对象的class,如String.class,Integer.Class,Double.Class
     * @return 返回类型
     */
    <E> E querySingleObject(String sql, Object params, Class<E> clz, boolean strictMode);

    /**
     * sql查询，适用查询结果为单行的场景；
     * 如果sql语句中只有一列,那jsonarray中存放的是该列的数组["1","2","3"...] 如果sql语句中返回不止一列,那么jsonarray中存放的是该列的json对象,例如 [{name:"1",age:"19"}...].
     *
     * @param sql    sql查询语句,
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合的json字符串。
     */
    default String querySingleString(String sql, Map<String, Object> params) {
        return JSONObject.toJSONString(queryMapList(sql, params));
    }

    /**
     * sql查询,用查询结果单行的场景；
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回查询结果的第一列的集合, 列名全部小写
     */
    default Map<String, Object> querySingleMap(String sql, Map<String, Object> params) {
        return querySingleObject(sql, params, Map.class, false);
    }

    /**
     * sql查询,用查询结果单行的场景；
     *
     * @param sql        sql语句
     * @param params     参数键值对,in/not in的参数 是数组
     * @param strictMode 严格模式  true时严格模式，返回多条则抛出异常，false时返回第一行
     * @return 返回查询结果的第一列的集合, 列名全部小写
     */
    default Map<String, Object> querySingleMap(String sql, Map<String, Object> params, boolean strictMode) {
        return querySingleObject(sql, params, Map.class, strictMode);
    }

    /**
     * sql查询.
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合
     */
    List<Map<String, Object>> queryMapList(String sql, Map<String, Object> params);

    /**
     * sql查询.
     *
     * @param sql             sql语句
     * @param params          参数键值对,in/not in的参数 是数组
     * @param pageNum         分页页数
     * @param pageSize        分页数量
     * @param isTotalRequired 是否返回总数
     * @return 返回PageResult对象，如果isTotalRequired为true 则返回总数；getTotalRow:总数；getList:数据集合;getTotalPage 总页数；
     */
    PageResult<Map<String, Object>> queryMapListPageable(String sql, Map<String, Object> params, int pageNum, int pageSize, boolean isTotalRequired);

    /**
     * sql查询.
     *
     * @param sql             sql语句
     * @param params          参数键值对,in/not in的参数 是数组
     * @param pageNum         分页页数
     * @param pageSize        分页数量
     * @param isTotalRequired 是否返回总数
     * @return 返回PageResult对象，如果isTotalRequired为true 则返回总数；getTotalRow:总数；getList:数据集合;getTotalPage 总页数；
     */
    <E> PageResult<E> queryEntityListPageable(String sql, Map<String, Object> params, int pageNum, int pageSize, boolean isTotalRequired, Class<E> clz);

    /**
     * 根据sql查询对象集合
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回指定的clz对象的集合
     */
    default <E> List<E> queryEntityList(String sql, Map<String, Object> params, Class<E> clz) {
        return queryEntityList(sql, (Object) params, clz);
    }

    /**
     * 根据sql查询对象集合
     *
     * @param sql    sql语句
     * @param params 参数键值对,in/not in的参数 是数组
     * @return 返回指定的clz对象的集合
     */
    <E> List<E> queryEntityList(String sql, Object params, Class<E> clz);

    /**
     * sql查询,适用查询结果单行的场景；使用Markdown格式来组织SQL文件
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回查询结果
     */
    <E> E querySingleObjectFromMarkdown(String fileName, String sqlMark, Map<String, Object> params, Class<E> clz);


    /**
     * sql查询,用查询结果单行的场景；使用Markdown格式来组织SQL文件
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回查询结果的第一列的集合, 列名全部小写
     */
    default Map<String, Object> querySingleMapFromMarkdown(String fileName, String sqlMark, Map<String, Object> params) {
        return querySingleObjectFromMarkdown(fileName, sqlMark, params, Map.class);
    }


    /**
     * sql查询，适用查询结果为单行的场景；使用Markdown格式来组织SQL文件
     * 如果sql语句中只有一列,那jsonarray中存放的是该列的数组["1","2","3"...] 如果sql语句中返回不止一列,那么jsonarray中存放的是该列的json对象,例如 [{name:"1",age:"19"}...].
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合的json字符串。
     */
    default String querySingleStringFromMarkdown(String fileName, String sqlMark, Map<String, Object> params) {
        return JSONObject.toJSONString(queryMapListFromMarkDown(fileName, sqlMark, params));
    }

    /**
     * 使用Markdown格式来组织SQL文件
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合, 列名全部小写
     */
    List<Map<String, Object>> queryMapListFromMarkDown(String fileName, String sqlMark, Map<String, Object> params);

    /**
     * 使用Markdown格式来组织SQL文件
     *
     * @param fileName SQL查询所在的文件名
     * @param sqlMark  SQL标记
     * @param params   参数键值对,in/not in的参数 是数组
     * @return 返回结果是列名为key, 值为value的map的list集合, 列名全部小写
     */
    <E> List<E> queryEntityListFromMarkDown(String fileName, String sqlMark, Map<String, Object> params, Class<E> clz);

    /**
     * 根据主键删除，需要严格匹配EntityClass.
     *
     * @param key   主键
     * @param clazz EntityClass类型
     */
    <E> void deleteEntityByKey(Serializable key, Class<E> clazz);

    /**
     * 存在该对象则更新，不存在则增加.
     *
     * @param entity 任意类型对象
     * @return 主键
     */
    <E> Object saveEntity(E entity);

    /**
     * 批量更新or新增，通过主键来判断是新增还是删除
     *
     * @param list 对象/实体列表
     */
    <E> void saveBatch(List<E> list);

    /**
     * 批量新增或更新；
     * TODO 已对Mysql进行了处理，Oracle，达梦（DM），人大金仓（Kingbase） 是使用  MERGE 的方式；神州通用（KingBaseES）不能使用 values 函数
     *
     * @param list           实体列表
     * @param uniqueKeyNames 数据库表对应的：组合唯一索引的实体字段
     * @param <E>            实体类型
     */
    <E> void upsertByKey(List<E> list, String[] uniqueKeyNames);

    /**
     * 新增或查询，需要注意：
     * uniqueKeyNames如果包含了主键，主键被申明@Autoid和@SeqID正常新增；@AssignID时无法进行新增；
     *
     * @param obj            实体对象
     * @param uniqueKeyNames 数据库表对应的：组合唯一索引的实体字段
     */
    <E> void upsertByKey(E obj, String[] uniqueKeyNames);

    /**
     * 部分更新，实体类中属性为Null或不传入的则不被更新
     *
     * @param list 任意类型对象List,未考虑到数据库能接收的最大量，因此，还需要程序自己控制每批的数量，设置成每批3000个比较通用
     */
    <E> void updateBatchIfNotNull(Class clazz, List<E> list);

    /************************delete data api ************************/
    /**
     * 删除任意类型对象.
     *
     * @param entity 任意类型对象
     */
    <E> void deleteEntity(E entity);

    /************************add data api ************************/

    /**
     * 添加对象，不需要严格匹配EntityClass，返回对象的主键.
     *
     * @param entity 实体
     * @return 主键
     */
    <E> Object addEntity(E entity);

    /************************update data api ************************/

    /**
     * 更新操作，不需要严格匹配EntityClass.
     *
     * @param entity 实体
     * @return 主键
     */
    <E> Object updateEntity(E entity);


    /**
     * 批量更新操作
     *
     * @param list 实体列表
     * @return 主键
     */
    <E> void updateBatch(List<E> list);

    /**
     * 部分更新，实体类中属性为Null则不被更新，
     * 注意注意：若实体中使用了存在默认值的类型，如下
     * byte：默认值为 0
     * short：默认值为 0
     * int：默认值为 0
     * long：默认值为 0L
     * float：默认值为 0.0f
     * double：默认值为 0.0d
     * char：默认值为 '\u0000'（空字符）
     * boolean：默认值为 false
     * 在使用部分更新时，若没有显式的赋值，会将数据库更新为默认值，请使用updateifNotNull(Class target, Object obj)
     *
     * @param entity 任意类型对象
     */
    <E> void updateIfNotNull(E entity);

    /**
     * 数据库操作.
     *
     * @param sql      sql语句
     * @param valuemap 参数键值对,注意:in/not in的参数 是数组
     * @return 返回执行行数
     */
    Integer sqlOperater(String sql, Map valuemap);


    /**Lambda 表达式*/

    /**
     * 查询（根据 columnMap 条件）
     *
     * @param columnMap 表字段 map 对象
     */
    default List<T> selectByMap(Map<String, Object> columnMap) {
        return this.selectList(Wrappers.<T>query().allEq(columnMap));
    }

    /**
     * 根据 entity 条件，查询一条记录
     * <p>查询一条记录，例如 qw.last("limit 1") 限制取一条记录, 注意：多条数据会报异常</p>
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default T selectOne(Wrapper<T> queryWrapper) {
        return this.selectOne(queryWrapper, true);
    }

    /**
     * 根据 entity 条件，查询一条记录，现在会根据{@code throwEx}参数判断是否抛出异常，如果为false就直接返回一条数据
     * <p>查询一条记录，例如 qw.last("limit 1") 限制取一条记录, 注意：多条数据会报异常</p>
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     * @param throwEx      boolean 参数，为true如果存在多个结果直接抛出异常
     */
    T selectOne(Wrapper<T> queryWrapper, boolean throwEx);

    /**
     * 根据 Wrapper 条件，判断是否存在记录
     *
     * @param queryWrapper 实体对象封装操作类
     * @return 是否存在记录
     */
    default boolean exists(Wrapper<T> queryWrapper) {
        Long count = this.selectCount(queryWrapper);
        return null != count && count > 0;
    }

    /**
     * 根据 Wrapper 条件，查询总记录数
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    Long selectCount(Wrapper<T> queryWrapper);

    /**
     * 根据 Wrapper 条件，查询总记录数
     *
     * @param clz          查哪个表
     * @param <E>          被查的POJO表名
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    <E> Long selectCount(Wrapper<T> queryWrapper, Class<E> clz);

    /**
     * 根据 entity 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    List<T> selectList(Wrapper<T> queryWrapper);

    /**
     * 根据 entity 条件，查询全部记录（并翻页）
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     * @since 1.0.0
     */
    <E, P extends PageRequest<E>> PageResult<E> selectList(P page, Wrapper<T> queryWrapper, Class<E> clz);

    /**
     * 根据 entity 条件，查询全部记录（并翻页）
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     * @since 1.0.0
     */
    PageResult<T> selectList(PageRequest<T> page, Wrapper<T> queryWrapper);


    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类
     */
    List<Map<String, Object>> selectMaps(Wrapper<T> queryWrapper);


    /**
     * 根据 Wrapper 条件，查询全部记录（并翻页）
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类
     * @since 1.0.0
     */
    <P extends PageRequest<Map>> List<Map<String, Object>> selectMaps(P page, Wrapper<T> queryWrapper);

    /**
     * 根据 Wrapper 条件，查询全部记录
     * <p>注意： 只返回第一个字段的值</p>
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default <E> List<E> selectObjs(Wrapper<T> queryWrapper, Class<E> clz) {
        return selectList(null, queryWrapper, clz).getList();
    }

    /**
     * 根据 Wrapper 条件，查询全部记录
     * <p>注意： 只返回第一个字段的值</p>
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default List<T> selectObjs(Wrapper<T> queryWrapper) {
        return selectList(null, queryWrapper).getList();
    }

    /**
     * 根据 entity 条件，查询全部记录（并翻页）
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default <P extends PageRequest<T>> PageResult<T> selectPage(P page, Wrapper<T> queryWrapper) {
        return selectList(page, queryWrapper);
    }

    /**
     * 根据 entity 条件，查询全部记录（并翻页）
     *
     * @param pageNum      分页查询条件
     * @param pageSize     分页查询条件
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default PageResult<T> selectPage(int pageNum, int pageSize, Wrapper<T> queryWrapper) {
        return selectList(DefaultPageRequest.of(pageNum, pageSize, true), queryWrapper);
    }

    /**
     * 根据 Wrapper 条件，查询全部记录（并翻页）
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类
     */
    default <P extends PageRequest<Map>> PageResult<Map> selectMapsPage(P page, Wrapper<T> queryWrapper) {
        return selectList(page, queryWrapper, Map.class);
    }

    /**
     * 根据 Wrapper 条件，查询全部记录（并翻页）
     *
     * @param pageNum      分页查询条件
     * @param pageSize     分页查询条件
     * @param queryWrapper 实体对象封装操作类
     */
    default PageResult<Map> selectMapsPage(int pageNum, int pageSize, Wrapper<T> queryWrapper) {
        return selectList(DefaultPageRequest.of(pageNum, pageSize, true), queryWrapper, Map.class);
    }

    /**
     * 根据 entity 条件，查询全部记录（并翻页）
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类（可以为 null）
     */
    default <P extends PageRequest<T>> PageResult<T> selectPage(P page, Wrapper<T> queryWrapper, boolean isTotal) {
        return selectList(DefaultPageRequest.of(page.getPageNumber(), page.getPageSize(), isTotal), queryWrapper);
    }

    /**
     * 根据 Wrapper 条件，查询全部记录（并翻页）
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类
     */
    default <P extends PageRequest<Map>> PageResult<Map> selectMapsPage(P page, Wrapper<T> queryWrapper, boolean isTotal) {
        return selectList(DefaultPageRequest.of(page.getPageNumber(), page.getPageSize(), isTotal), queryWrapper, Map.class);
    }

    /**
     * 根据 columnMap 条件，删除记录
     *
     * @param columnMap 表字段 map 对象
     */
    default int deleteByMap(Map<String, Object> columnMap) {
        return this.delete(Wrappers.<T>query().allEq(columnMap));
    }

    /**
     * 根据 entity 条件，删除记录
     *
     * @param queryWrapper 实体对象封装操作类（可以为 null,里面的 entity 用于生成 where 语句）
     */
    int delete(Wrapper<T> queryWrapper);

    /**
     * 根据 whereEntity 条件，更新记录
     *
     * @param entity  实体对象 (set 条件值,可以为 null,当entity为null时,无法进行自动填充)
     * @param wrapper 实体对象封装操作类（可以为 null,里面的 entity 用于生成 where 语句）
     */
    <E> int update(E entity, Wrapper<E> wrapper);

    /**
     * 根据 Wrapper 更新记录
     * <p>此方法无法进行自动填充,如需自动填充请使用{@link #update(Object, Wrapper)} </p>
     *
     * @param updateWrapper {@link UpdateWrapper} or {@link LambdaUpdateWrapper}
     */
    default int update(Wrapper<T> updateWrapper) {
        return update(null, updateWrapper);
    }


    /**
     * 链式查询 普通
     *
     * @return QueryWrapper 的包装类
     */
    default QueryChainWrapper<T> query() {
        return ChainWrappers.queryChain(getBaseDao());
    }

    /**
     * 链式查询 lambda 式
     * <p>注意：不支持 Kotlin </p>
     *
     * @return LambdaQueryWrapper 的包装类
     */
    default LambdaQueryChainWrapper<T> lambdaQuery() {
        return ChainWrappers.lambdaQueryChain(getBaseDao(), getEntityClass());
    }

    /**
     * 链式查询 lambda 式
     * <p>注意：不支持 Kotlin </p>
     *
     * @param entity 实体对象
     * @return LambdaQueryWrapper 的包装类
     */
    default LambdaQueryChainWrapper<T> lambdaQuery(T entity) {
        return ChainWrappers.lambdaQueryChain(getBaseDao(), entity);
    }

    /**
     * 链式更改 普通
     *
     * @return UpdateWrapper 的包装类
     */
    default UpdateChainWrapper<T> update() {
        return ChainWrappers.updateChain(getBaseDao());
    }

    /**
     * 链式更改 lambda 式
     * <p>注意：不支持 Kotlin </p>
     *
     * @return LambdaUpdateWrapper 的包装类
     */
    default LambdaUpdateChainWrapper<T> lambdaUpdate() {
        return ChainWrappers.lambdaUpdateChain(getBaseDao());
    }

    /**
     * 根据 Wrapper 条件，连表删除
     *
     * @param wrapper joinWrapper
     */
    int deleteJoin(Wrapper<T> wrapper);

    /**
     * 根据 whereEntity 条件，更新记录
     *
     * @param entity  实体对象 (set 条件值,可以为 null)
     * @param wrapper 实体对象封装操作类（可以为 null,里面的 entity 用于生成 where 语句）
     */
    int updateJoin(T entity, Wrapper<T> wrapper);

    /**
     * 根据 whereEntity 条件，更新记录 (null字段也会更新 !!!)
     *
     * @param entity  实体对象 (set 条件值,可以为 null)
     * @param wrapper 实体对象封装操作类（可以为 null,里面的 entity 用于生成 where 语句）
     */
    int updateJoinAndNull(T entity, Wrapper<T> wrapper);

    /**
     * 根据 Wrapper 条件，查询总记录数
     *
     * @param wrapper joinWrapper
     */
    Long selectJoinCount(Wrapper<T> wrapper);

    /**
     * 连表查询返回一条记录
     *
     * @param wrapper joinWrapper
     * @return T
     */
    default T selectJoinOne(Wrapper<T> wrapper) {
        return selectJoinOne(null, wrapper);
    }

    /**
     * 连表查询返回一条记录
     *
     * @param wrapper joinWrapper
     * @param clazz   resultType
     */
    default <DTO> DTO selectJoinOne(Class<DTO> clazz, Wrapper<T> wrapper) {
        PageResult page = selectJoinPage(DefaultPageRequest.of(0, 1, false), clazz, wrapper);
        List<DTO> list = page.getList();
        if (list.isEmpty()) {
            return null;
        } else {
            return list.get(0);
        }
    }

    /**
     * 连表查询返回Map
     *
     * @param wrapper joinWrapper
     */
    default Map<String, Object> selectJoinMap(Wrapper<T> wrapper) {
        //noinspection unchecked
        return selectJoinOne(Map.class, wrapper);
    }

    /**
     * 连表查询返回记录集合
     *
     * @param wrapper joinWrapper
     * @return List&lt;T&gt;
     */
    default List<T> selectJoinList(Wrapper<T> wrapper) {
        return selectJoinList(null, wrapper);
    }

    /**
     * 连表查询返回记录集合
     *
     * @param wrapper joinWrapper
     * @param clazz   resultType
     */
    default <DTO> List<DTO> selectJoinList(Class<DTO> clazz, Wrapper<T> wrapper) {
        return selectJoinPage(null, clazz, wrapper).getList();
    }

    /**
     * 连表查询返回Map集合
     *
     * @param wrapper joinWrapper
     */
    default List<Map<String, Object>> selectJoinMaps(Wrapper<T> wrapper) {
        return (List<Map<String, Object>>) ((Object) selectJoinList(Map.class, wrapper));
    }

    /**
     * 连表查询返回记录集合并分页
     *
     * @param wrapper joinWrapper
     */
    default <P extends PageRequest<T>> PageResult<T> selectJoinPage(P page, Wrapper<T> wrapper) {
        return selectJoinPage(page, null, wrapper);
    }

    /**
     * 连表查询返回记录集合并分页
     *
     * @param wrapper joinWrapper
     * @param clazz   resultType
     * @param <DTO>   分页返回对象
     */
    <DTO, P extends PageRequest<DTO>> PageResult<DTO> selectJoinPage(P page, Class<DTO> clazz, Wrapper<T> wrapper);

    /**
     * 连表查询返回Map集合并分页
     *
     * @param wrapper joinWrapper
     */
    default <P extends PageRequest<Map>> PageResult<Map<String, Object>> selectJoinMapsPage(P page, Wrapper<T> wrapper) {
        PageResult<Map> res = selectJoinPage(page, Map.class, wrapper);
        PageRequest request = DefaultPageRequest.of(page.getPageNumber(), page.getPageSize(), page.isTotalRequired(), page.isListRequired());
        PageResult<Map<String, Object>> result = request.of(BeetlUtils.convertResult(res.getList()), res.getTotalRow());
        return result;
    }
}
